package cc.minos.console
{
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.ContextMenuEvent;
	import flash.events.Event;
	import flash.external.ExternalInterface;
	import flash.net.FileReference;
	import flash.ui.ContextMenu;
	import flash.ui.ContextMenuItem;
	import flash.utils.getQualifiedClassName;
	
	/**
	 * ...
	 * @author Minos
	 */
	public class Console
	{
		
		public static const INFO:Number = 0;
		public static const DEBUG:Number = 1;
		public static const WARNING:Number = 2;
		public static const ERROR:Number = 3;
		public static const FATAL:Number = 4;
		
		private static var stage:Stage;
		private static var viewer:ConsoleViewer;
		private static var checker:CheckBox;
		
		protected static var file:FileReference;
		
		//private static var initialized:Boolean = false;
		
		public static function apply( app:Sprite , psw:String = null , v:ConsoleViewer = null ):void
		{
			if ( Console.stage )
				return;
			Console.stage = app.stage;
			
			if ( v == null )
				viewer = new ConsoleViewer( stage.stageWidth , 200 );
			else
				viewer = v;
				
			if( psw ){
				checker = new CheckBox( psw );
				checker.addEventListener( 'check' , function( e:Event ):void
					{
						stage.removeChild( checker );
						if ( checker.isPass )
							toggle();
					} );
			}
			
			var menu:ContextMenu = app.contextMenu;
			if ( !menu )
				menu = new ContextMenu();
			var c:ContextMenuItem = new ContextMenuItem( "Console v" + ConsoleSettting.VERSION );
			menu.customItems.push( c );
			app.contextMenu = menu;
			c.addEventListener( ContextMenuEvent.MENU_ITEM_SELECT , onConsoleSelected );
			stage.addEventListener( Event.RESIZE , onResize );
			//initialized = true;
			
		}
		
		static private function onResize( e:Event ):void
		{
			viewer.width = stage.stageWidth;
			viewer.y = stage.stageHeight - viewer.height;
		}
		
		static private function onConsoleSelected( e:ContextMenuEvent ):void
		{
			toggle();
		}
		
		public static function log( msg:* , from:Object = null , level:int = 0 , author:String = "" ):void
		{
			var str:String = "";
			if ( author != "" )
			{
				str += author.toUpperCase() + " - ";
			}
			
			try{
				if ( !from )
					str += "[" + new Error().getStackTrace().match( /[\w\/]*\(\)/g )[ 1 ] + "] ";
				else
					str += from.toString();
			}catch (er:Error) { };
			str += msg;
			
			/*  output  */
			trace( str ); //debug
			if ( ConsoleSettting.chrome && ExternalInterface.available )
				ExternalInterface.call("console.log" , str ); //chrome console.log
			if ( viewer )
				viewer.appendText( str , level ); //ui
		}
		
		public static function logArray( msg:Array , from:Object , level:int = 0 , author:String = "" , dep:int = 0 ):void
		{
			var le:int = msg.length;
			var prefix:String = "";
			var type:Object;
			type = getQualifiedClassName( msg[ i ] );
			
			for ( var j:int = 0 ; j < dep ; j++ )
			{
				prefix += "- ";
			}
			
			if ( !from )
				from = "[" + new Error().getStackTrace().match( /[\w\/]*\(\)/g )[ 1 ] + "]";
			
			for ( var i:int = 0 ; i < le ; i++ )
			{
				
				if ( type == "Array" )
				{
					log( prefix + "- [" + i + "] => Array (" + msg[ i ].length + ")" , from , level , author );
					logArray( msg[ i ] , from , level , author , dep + 1 );
				}
				else if ( type == "Object" )
				{
					log( prefix + "- [" + i + "] => Object" , from , level , author );
					logObject( msg[ i ] , from , level , author , dep + 2 );
				}
				else
				{
					log( prefix + "- [" + i + "] => " + msg[ i ] , from , level , author );
				}
			}
		}
		
		public static function logObject( msg:Object , from:Object = null , level:int = 0 , author:String = "" , dep:int = 0 ):void
		{
			var prefix:String = "";
			var type:Object;
			
			for ( var i:int = 0 ; i < dep ; i++ )
			{
				prefix += "- ";
			}
			
			if ( !from )
				from = "[" + new Error().getStackTrace().match( /[\w\/]*\(\)/g )[ 1 ] + "]";
			
			for ( var p:*in msg )
			{
				type = getQualifiedClassName( msg[ p ] );
				if ( type == "Array" )
				{
					log( prefix + "- [" + p + "] => Array" , from , level , author );
					logArray( msg[ p ] , from , level , author , dep + 1 );
				}
				else if ( type == "Object" )
				{
					log( prefix + "- [" + p + "] => Object" , from , level , author );
					logObject( msg[ p ] , from , level , author , dep + 1 );
				}
				else
				{
					log( prefix + "- [" + p + "] => " + msg[ p ] , from , level , author );
				}
			}
		}
		
		public static function saveLog():void
		{
			var date:Date = new Date();
			var filename:String = "CONSOLE-LOG-" + date.fullYear + "-" + ((( date.month + 1 ) < 10 ) ? "0" + ( date.month + 1 ) : date.month ) + "-" + (( date.date < 10 ) ? "0" + date.date : date.date ) + "-" + (( date.hours < 10 ) ? "0" + date.hours : date.hours ) + (( date.minutes < 10 ) ? "0" + date.minutes : date.minutes ) + ".txt";
			file = new FileReference();
			file.save( viewer.getLog() , filename );
		}
		
		public static function toggle():void
		{
			if ( viewer && stage && stage.contains( viewer ) )
			{
				stage.removeChild( viewer );
			}
			else if ( checker == null || checker.isPass )
			{
				viewer.y = stage.stageHeight - viewer.height;
				stage.addChild( viewer );
			}
			else
			{
				checker.x = ( stage.stageWidth - checker.width ) * .5;
				checker.y = ( stage.stageHeight - checker.height ) * .5;
				stage.addChild( checker );
			}
		}
	}
}